using System;
using System.Collections.Generic;
using Microsoft.DirectX;
using RPGOnline.Controls.Map.Layers.Lighting;

namespace RPGOnline.Controls.Map.Layers
{
    public class ObstructionTile
    {
        private readonly Map m_map;
        private List<ObstructionEdge> m_obstructingEdges = new List<ObstructionEdge>();
        private Vector2 m_tileCenter = new Vector2(0,0);

        public ObstructionTile(Map map)
        {
            m_map = map;
        }

        public void UpdateObstructions(ObstructionTile[,] obstructions, MapCell mapCell, int x, int y)
        {
            m_obstructingEdges.Clear();

            if (mapCell.ObstructionLines.Count != 0)
            {
                //TODO: Remove all the edge lines covered by neighbour' shadows
                foreach (ObstructionLine obstructionLine in mapCell.ObstructionLines)
                {
                    ObstructionEdge[] edges = obstructionLine.GetEdges(x*m_map.TileSize.Width, y*m_map.TileSize.Height);
                    m_obstructingEdges.AddRange(edges);
                }
            }
            else
            {
                if (x + 1 < m_map.MapSize.Width && obstructions[x + 1, y] == null)
                    m_obstructingEdges.Add(new ObstructionEdge(m_map, x, y, ObstructionSide.Right));

                if (x - 1 >= 0 && obstructions[x - 1, y] == null)
                    m_obstructingEdges.Add(new ObstructionEdge(m_map, x, y, ObstructionSide.Left));

                if (y + 1 < m_map.MapSize.Height && obstructions[x, y + 1] == null)
                    m_obstructingEdges.Add(new ObstructionEdge(m_map, x, y, ObstructionSide.Bottom));

                if (y - 1 >= 0 && obstructions[x, y - 1] == null)
                    m_obstructingEdges.Add(new ObstructionEdge(m_map, x, y, ObstructionSide.Top));
            }

            m_tileCenter = new Vector2(
                x * m_map.TileSize.Width + (m_map.TileSize.Width / 2),
                y * m_map.TileSize.Height + (m_map.TileSize.Height / 2)
            );
        }

        public bool WillCastShadows(Light light)
        {
            float distance = (light.Position - m_tileCenter).Length();
            if (distance > light.Radius)
                return false;

            foreach (ObstructionEdge obstructingEdge in m_obstructingEdges)
            {
                if (!obstructingEdge.IsFacingLight(light))
                    return true;
            }

            return false;
        }

        public List<ShadowPolygon> CastShadows(Light light)
        {
            List<ShadowPolygon> shadowPolygons = new List<ShadowPolygon>();
            foreach (ObstructionEdge obstructingEdge in m_obstructingEdges)
            {
                if(!obstructingEdge.IsFacingLight(light))
                {
                    shadowPolygons.Add(obstructingEdge.CreateShadowPolygon(light));
                }
            }

            return shadowPolygons;
        }

        public List<ShadowPolygon> CastDebugShadows(Light light)
        {
            List<ShadowPolygon> shadowPolygons = new List<ShadowPolygon>();
            foreach (ObstructionEdge obstructingEdge in m_obstructingEdges)
            {
                if (!obstructingEdge.IsFacingLight(light))
                {
                    shadowPolygons.Add(obstructingEdge.CreateDebugShadowPolygon(light));
                }
            }

            return shadowPolygons;
        }
    }
}